package com.netvine.iias;

import de.onvif.soap.OnvifDevice;
import de.onvif.soap.devices.MediaDevices;
import de.onvif.soap.devices.PtzDevices;
import org.onvif.ver10.schema.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.xml.soap.SOAPException;
import java.net.ConnectException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

@Service
public class ONVIFService implements SDKservice {
    private static final Logger log = LoggerFactory.getLogger(run.class);
    @Value("${nvr.ip}")
    private String ip;

    @Value("${nvr.port}")
    private Integer port;

    @Value("${nvr.account}")
    private String account;

    @Value("${nvr.password}")
    private String password;

    @Override
    public List<CameraInfo> getCameraList() throws SOAPException, ConnectException {
        ArrayList<CameraInfo> cameraInfos = new ArrayList<>();
        OnvifDevice onvifDevice = new OnvifDevice(ip, account, password);
        List<Profile> profiles = onvifDevice.getDevices().getProfiles();
        for (Profile profile : profiles) {
            if (profile.getName().contains("MainStream")) {
                CameraInfo cameraInfo = new CameraInfo();
                cameraInfo.setName(profile.getName());
                cameraInfo.setChanNum(profile.getToken());
                String profileToken = profile.getToken();
                MediaDevices mediaDevices = onvifDevice.getMedia();
                // 获取rtsp流
                StreamSetup setup = new StreamSetup();
                setup.setStream(StreamType.RTP_UNICAST);
                Transport transport = new Transport();
                transport.setProtocol(TransportProtocol.RTSP);
                setup.setTransport(transport);
                String RTSPUrl = mediaDevices.getStreamUri(profileToken, setup);
                System.out.println("RTSPUrl:" + RTSPUrl);
                String[] split = RTSPUrl.split("/");
                String rest = "";
                for (int i = 2; i < split.length; i++) {
                    rest += "/";
                    rest += split[i];
                }
                String rtsp = "rtsp://" + account + ":" + password + rest;
                cameraInfo.setRtsp(rtsp);
                cameraInfos.add(cameraInfo);
            }
        }
        return cameraInfos;
    }

    @Override
    public Result PTZControl(PtzDto ptzDto) throws SOAPException, ConnectException {
        OnvifDevice onvifDevice = new OnvifDevice(ip, account, password);
        if (!StringUtils.isEmpty(ptzDto.getChanNum())) {
            PtzDevices ptzDevices = onvifDevice.getPtz();
            if (ptzDto.getIsStop() == 0) {
                ptzDevices.continuousMove(ptzDto.getChanNum(), getPanSpeed(ptzDto),
                        getTiltSpeed(ptzDto), getZoomSpeed(ptzDto));
            } else {
                ptzDevices.stopMove(ptzDto.getChanNum());
            }
        }
        return Result.ok();
    }

    @Override
    public Result zoomControl(PtzDto ptzDto) throws SOAPException, ConnectException {
        OnvifDevice onvifDevice = new OnvifDevice(ip, account, password);
        if (!StringUtils.isEmpty(ptzDto.getChanNum())) {
            PtzDevices ptzDevices = onvifDevice.getPtz();
            if (ptzDto.getIsStop() == 0) {
                ptzDevices.continuousMove(ptzDto.getChanNum(), getPanSpeed(ptzDto),
                        getTiltSpeed(ptzDto), getZoomSpeed(ptzDto));
            } else {
                ptzDevices.stopMove(ptzDto.getChanNum());
            }
        }
        return Result.ok();
    }

    @Override
    public Result presetPoint(PtzDto ptzDto) throws SOAPException, ConnectException {
        OnvifDevice onvifDevice = new OnvifDevice(ip, account, password);
        PtzDevices ptzDevices = onvifDevice.getPtz();
        List<PTZPreset> presets = ptzDevices.getPresets(ptzDto.getChanNum());
        if (!presets.isEmpty()) {
            Optional<PTZPreset> preset = presets.stream()
                    .filter(p -> p.getName().equals("20"))
                    .findFirst();
            if (preset.isPresent()) {
                // 移动到预置点
                ptzDevices.gotoPreset(preset.get().getToken(), ptzDto.getChanNum());
            }
        }else {
            ptzDevices.setPreset("20", ptzDto.getChanNum());
        }
        return Result.ok();
    }

    private Float getPanSpeed(PtzDto ptzDto) {
        if (!ptzDto.getCommand().contains("RIGHT") && !ptzDto.getCommand().contains("LEFT")) {
            // 竖直旋转
            return 0F;
        }
        if (ptzDto.getCommand().contains("LEFT")) {
            return -0.2F;
        } else {
            return 0.2F;
        }
    }

    private Float getTiltSpeed(PtzDto ptzDto) {
        if (!ptzDto.getCommand().contains("UP") && !ptzDto.getCommand().contains("DOWN")) {
            // 水平旋转
            return 0F;
        }
        if (ptzDto.getCommand().contains("DOWN")) {
            return -0.2F;
        } else {
            return 0.2F;
        }
    }

    private Float getZoomSpeed(PtzDto entity) {
        if (!entity.getCommand().contains("ZOOM")) {
            return 0F;
        }
        if (entity.getCommand().contains("IN")) {
            // 放大
            return 0.5F;
        } else {
            return -0.5F;
        }
    }

    private void gotoPreset(List<PTZPreset> presets, String profileToken, PtzDevices ptzDevices) {
        if (!presets.isEmpty()) {
            Optional<PTZPreset> preset = presets.stream()
                    .filter(p -> p.getName().equals("1"))
                    .findFirst();
            if (preset.isPresent()) {
                ptzDevices.gotoPreset(preset.get().getToken(), profileToken);
                log.info("已到达预置点1");
            }
        }
    }
}
